package cn.virens.common.mybatis.dynamic_table;

import cn.virens.common.mybatis.dynamic_table.proxy.DynamicTableNameProxyBuddy;
import cn.virens.common.mybatis.dynamic_table.proxy.DynamicTableNameProxyCglib;
import cn.virens.common.util.core.Assert;
import cn.virens.common.util.exception.APIException;
import cn.virens.common.util.exception.ExceptionUtil;
import io.mybatis.provider.EntityTable;
import io.mybatis.provider.EntityTableFactory;
import org.dromara.hutool.core.classloader.ClassLoaderUtil;
import org.dromara.hutool.core.text.StrUtil;

import java.util.function.Supplier;

public class DynamicTableNameFactory implements EntityTableFactory {
    private boolean supportCglib = ClassLoaderUtil.isPresent("net.sf.cglib.proxy.Enhancer");
    private boolean supportBuddy = ClassLoaderUtil.isPresent("net.bytebuddy.ByteBuddy");

    private final static DynamicTableNameLocal local = new DynamicTableNameLocal();

    @Override
    public EntityTable createEntityTable(Class<?> entityClass, Chain chain) {
        EntityTable r = chain.createEntityTable(entityClass);
        if (r != null && StrUtil.isNotEmpty(r.table())) {
            return ExceptionUtil.e1(() -> proxy(r));
        }

        return r;
    }

    private EntityTable proxy(EntityTable entityTable) throws Exception {
        if (supportBuddy) {
            return DynamicTableNameProxyBuddy.buildProxy(entityTable);
        }
        if (supportCglib) {
            return DynamicTableNameProxyCglib.buildProxy(entityTable);
        }

        return entityTable;
    }

    /**
     * 设置动态表名变量(当前线程/子线程有效)
     *
     * @param key      关键词
     * @param supplier 供应者
     */
    public static void variable(String key, Supplier<String> supplier) {
        local.variable(Assert.isEmpty(key), supplier);
    }

    /**
     * 设置动态表名变量(当前线程/子线程有效)
     *
     * @param key   关键词
     * @param value 替换值
     */
    public static void variable(String key, String value) {
        local.variable(Assert.isEmpty(key), value);
    }

    /**
     * 生成动态表名
     */
    public static String generate(String table) throws APIException {
        return local.generateDynamicTableName(table);
    }

    /**
     * 清理当前线程变量
     *
     * @throws APIException
     */
    public static void clean() throws APIException {
        local.remove();
    }

    @Override
    public int getOrder() throws APIException {
        return 100;
    }
}
